////////////////////////////////////////////////////////////////////////////
//
//  CryEngine Source File.
//  Copyright (C), Crytek, 1999-2011.
//
// -------------------------------------------------------------------------
//  File name:   FlowMusicMoodSelectorNode.h
//  Version:     v1.00
//  Created:     08/04/2011 by Thomas Wollenzin
//  Description: This is the implementation of the FlowMusicMoodSelectorNode class
//
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "FlowBaseNode.h"

class CFlowNode_MusicMoodSelector : public CFlowBaseNode<eNCT_Instanced>
{

public:

	//////////////////////////////////////////////////////////////////////////
	CFlowNode_MusicMoodSelector(SActivationInfo* pActInfo) 
	{
	}

	//////////////////////////////////////////////////////////////////////////
	~CFlowNode_MusicMoodSelector()
	{
	}

	//////////////////////////////////////////////////////////////////////////
	IFlowNodePtr Clone(SActivationInfo* pActInfo)
	{
		return new CFlowNode_MusicMoodSelector(pActInfo);
	}

	enum INPUTS 
	{
		eIN_SET_MOOD,
		eIN_GET_MOOD,
		eIN_MOOD,
		eIN_PLAY_SYNCED,
		eIN_HIGHER_MOOD,
		eIN_LOWER_MOOD,

		eIN_NUM_PORTS
	};

	enum OUTPUTS 
	{
		eOUT_CURRENT_MOOD,
		eOUT_SILENCE,
		eOUT_INCIDENTAL,
		eOUT_AMBIENT,
		eOUT_TENSION,
		eOUT_ACTION,
		eOUT_FRANTIC,

		eOUT_NUM_PORTS
	};

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void GetConfiguration(SFlowNodeConfig& config)
	{
		static const SInputPortConfig inputs[] = 
		{
			InputPortConfig_Void("SetMood", _HELP("Sets the supplied mood."), "SetMood"),
			InputPortConfig_Void("GetMood", _HELP("Gets the currently set mood."), "GetMood"),
			InputPortConfig<string>("Mood", _HELP("Set the name for the mood here!"), "Mood"),
			InputPortConfig<bool>("PlaySynced", true, _HELP("Indicates whether to start at the beginning or at the same time as the currently playing track."), "PlaySynced"),
			InputPortConfig_Void("HigherMood", _HELP("Switches to the next higher mood."), "HigherMood"),
			InputPortConfig_Void("LowerMood", _HELP("Switches to the next lower mood."), "LowerMood"),
			InputPortConfig_Null()
		};

		static const SOutputPortConfig outputs[] = 
		{
			OutputPortConfig_Void("Mood1", _HELP("Receives the name of the currently set mood when either SetMood or GetMood were triggered."), "CurrentMood"),
			OutputPortConfig_Void("Mood2", _HELP("Gets triggered when the \"Silence\" mood got set."), "Silence"),
			OutputPortConfig_Void("Mood3", _HELP("Gets triggered when the \"Incidental\" mood got set."), "Incidental"),
			OutputPortConfig_Void("Mood4", _HELP("Gets triggered when the \"Ambient\" mood got set."), "Ambient"),
			OutputPortConfig_Void("Mood5", _HELP("Gets triggered when the \"Tension\" mood got set."), "Tension"),
			OutputPortConfig_Void("Mood6", _HELP("Gets triggered when the \"Action\" mood got set."), "Action"),
			OutputPortConfig_Void("Mood7", _HELP("Gets triggered when the \"Frantic\" mood got set."), "Frantic"),
			OutputPortConfig_Null()
		};
		
		config.pInputPorts  = inputs;
		config.pOutputPorts = outputs;
		config.sDescription = _HELP("Music Mood Selector");
		config.SetCategory(EFLN_APPROVED);
	}

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void Serialize(SActivationInfo* pActivationInfo, TSerialize ser)
	{
	}

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void ProcessEvent(EFlowEvent event, SActivationInfo* pActInfo)
	{
		switch (event)
		{
		case eFE_Initialize:
			{
			}
			break;
		case eFE_Activate:
			{
				string const sCurrentMood(gEnv->pMusicSystem->GetMood());
				string const& sNewMood          = GetPortString(pActInfo, eIN_MOOD);
				bool const bSetMoodTriggered    = IsPortActive(pActInfo, eIN_SET_MOOD);
				bool const bGetMoodTriggered    = IsPortActive(pActInfo, eIN_GET_MOOD);
				bool const bHigherMoodTriggered = IsPortActive(pActInfo, eIN_HIGHER_MOOD);
				bool const bLowerMoodTriggered  = IsPortActive(pActInfo, eIN_LOWER_MOOD);

				if (bSetMoodTriggered || bGetMoodTriggered)
				{
					// If this is one of our standard moods activate the corresponding output port as well
					string const sTemp(bGetMoodTriggered ? sCurrentMood : sNewMood);
					OUTPUTS const eOutputPortID = GetOutPortMoodIDByMoodName(sTemp);

					if (eOutputPortID != eOUT_NUM_PORTS)
					{
						ActivateOutput(pActInfo, eOutputPortID, true);
					}

					// Forward this to the current mood port as well
					ActivateOutput(pActInfo, eOUT_CURRENT_MOOD, sTemp);
				}
				
				if (bSetMoodTriggered)
				{
					// Try to set the supplied mood
					bool const bPlaySynced = GetPortBool(pActInfo, eIN_PLAY_SYNCED);
					gEnv->pMusicSystem->SetMood(sNewMood.c_str(), !bPlaySynced);
				}
				else if (bHigherMoodTriggered || bLowerMoodTriggered)
				{
					// Determine the next higher/lower mood from the current one and set it
					TMoodsHierarchyVec const& aoMoodsHierarchy(gEnv->pMusicSystem->GetMusicMoodHierarchy());
					TMoodsHierarchyVec::const_iterator const IterEnd(aoMoodsHierarchy.end());

					for (TMoodsHierarchyVec::const_iterator Iter(aoMoodsHierarchy.begin()); Iter != IterEnd; ++Iter)
					{
						SMusicMoodHierarchy const* const pMoodHierarchy = &(*Iter);
						if (pMoodHierarchy->sMood.compareNoCase(sCurrentMood.c_str()) == 0)
						{
							bool const bSwitchToHigher = (!pMoodHierarchy->sHigherMood.empty() && bHigherMoodTriggered);
							bool const bSwitchToLower  = (!pMoodHierarchy->sLowerMood.empty() && bLowerMoodTriggered);
							bool const bPlaySynced     = GetPortBool(pActInfo, eIN_PLAY_SYNCED);

							if (bSwitchToHigher || bSwitchToLower)
							{
								// Both must not be true
								assert(bSwitchToHigher || bSwitchToLower);

								// Set the corresponding mood
								gEnv->pMusicSystem->SetMood(bSwitchToHigher ? pMoodHierarchy->sHigherMood.c_str() : pMoodHierarchy->sLowerMood.c_str(), !bPlaySynced);
								
								// Determine what's the next higher mood and activate the corresponding output port
								string const sTemp(bSwitchToHigher ? pMoodHierarchy->sHigherMood : pMoodHierarchy->sLowerMood);
								OUTPUTS const eOutputPortID = GetOutPortMoodIDByMoodName(sTemp);

								if (eOutputPortID != eOUT_NUM_PORTS)
								{
									ActivateOutput(pActInfo, eOutputPortID, true);
								}

								// Forward this to the current mood port as well
								ActivateOutput(pActInfo, eOUT_CURRENT_MOOD, sTemp);
							}
							
							break;
						}
					}
				}
			}
			break;
		}
	}

	//////////////////////////////////////////////////////////////////////////
	VIRTUAL void GetMemoryUsage(ICrySizer * s) const
	{
		s->Add(*this);
	}

	//////////////////////////////////////////////////////////////////////////
	OUTPUTS const GetOutPortMoodIDByMoodName(string const& sMood) const
	{
		if (sMood.compareNoCase("silence") == 0)
		{
			return eOUT_SILENCE;
		}
		else if (sMood.compareNoCase("incidental") == 0)
		{
			return eOUT_INCIDENTAL;
		}
		else if (sMood.compareNoCase("ambient") == 0)
		{
			return eOUT_AMBIENT;
		}
		else if (sMood.compareNoCase("tension") == 0)
		{
			return eOUT_TENSION;
		}
		else if (sMood.compareNoCase("action") == 0)
		{
			return eOUT_ACTION;
		}
		else if (sMood.compareNoCase("frantic") == 0)
		{
			return eOUT_FRANTIC;
		}

		return eOUT_NUM_PORTS;
	}
};

REGISTER_FLOW_NODE("Music:MoodSelector", CFlowNode_MusicMoodSelector);
